\newcommand{\ARMELF}{\InSqBrackets{\IT{ELF für die ARM 64-Bit-Architektur (AArch64)}, (2013)}\footnote{\AlsoAvailableAs
\url{http://go.yurichev.com/17288}}}

\subsection{Relocs in ARM64}
\label{ARM64_relocs}
Wie wir wissen, gibt es 4-Byte-Befehle in ARM64, sodass es unmöglich ist, eine große Zahl mit einem einzigen Befehl in
ein Register zu schreiben.

Nichtsdestotrotz kann eine Executable an jeder Adresse des Speichers geladen werden und das ist der Grund dafür, dass
Relocs existieren. Mehr dazu (in Bezug auf Win32 PE) unter: \myref{subsec:relocs}.

\myindex{ARM!\Instructions!ADRP/ADD pair}
Die Adresse wird in ARM64 aus einem \TT{ADRP} und \ADD Befehlspaar zusammengesetzt.

Der erste Befehl lädt eine 4KiB-Seitenadresse und der zweite den Rest. 
Kompilieren wir das Beispiel aus \q{\HelloWorldSectionName} (\lstref{hw_c}) in GCC (Linaro) 4.9 unter win32:

\begin{lstlisting}[caption=GCC (Linaro) 4.9 und objdump der Objektdatei,style=customasmARM]
...>aarch64-linux-gnu-gcc.exe hw.c -c

...>aarch64-linux-gnu-objdump.exe -d hw.o

...

0000000000000000 <main>:
   0:   a9bf7bfd        stp     x29, x30, [sp,#-16]!
   4:   910003fd        mov     x29, sp
   8:   90000000        adrp    x0, 0 <main>
   c:   91000000        add     x0, x0, #0x0
  10:   94000000        bl      0 <printf>
  14:   52800000        mov     w0, #0x0                        // #0
  18:   a8c17bfd        ldp     x29, x30, [sp],#16
  1c:   d65f03c0        ret

...>aarch64-linux-gnu-objdump.exe -r hw.o

...

RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE
0000000000000008 R_AARCH64_ADR_PREL_PG_HI21  .rodata
000000000000000c R_AARCH64_ADD_ABS_LO12_NC  .rodata
0000000000000010 R_AARCH64_CALL26  printf
\end{lstlisting}

Es gibt hier 3 Relocs in dieser Datei.

\begin{itemize}
\item 
Der erste nimmt die Seitenadresse, schneidet die niederstnen 12 Bits aus und schreibt die übrigen 21 Bit in das
Bitfield für den \TT{ADRP} Befehl. Das wird getan, weil wir die niedersten 12 Bit nicht kodieren und der Befehl
\INS{ADRP} nur Platz für 21 Bit hat.

\item 
Der zweite legt die 12 Bit der Adresse relativ zum Seitenanfang in das Bitfield des \ADD Befehls.

\item 
Der letzte mit 26 Bit wird auf den Befehl an der Adresse \TT{0x10} angewendet, an der sich der Sprung zur Funktion
\printf befindet.

Alle ARM64 (und ARM im ARM mode) Befehlsadressen haben Nullen in den zwei niederwertigsten Bits (da alle Befehle eine
Größe von 4 Byte haben), sodass man nur die höchsten 26 Bit eines 28-Bit-Adressraums ($\pm 128$MB) kodieren muss.

\end{itemize}
Solche Relocs gibt es in der ausführbaren Datei nicht: das liegt daran, dass bekannt ist, wo der \q{Hello!} String
abgelegt wurde; die Seiten und die Adresse von \puts sind ebenfalls bekannt.

In den Befehlen \TT{ADRP}, \ADD und \TT{BL} sind also bereits Werte gesetzt (der Linker hat diese während des Linkens
geschrieben):

\begin{lstlisting}[caption=objdump der ausführbaren Datei,style=customasmARM]
0000000000400590 <main>:
  400590:       a9bf7bfd        stp     x29, x30, [sp,#-16]!
  400594:       910003fd        mov     x29, sp
  400598:       90000000        adrp    x0, 400000 <_init-0x3b8>
  40059c:       91192000        add     x0, x0, #0x648
  4005a0:       97ffffa0        bl      400420 <puts@plt>
  4005a4:       52800000        mov     w0, #0x0                        // #0
  4005a8:       a8c17bfd        ldp     x29, x30, [sp],#16
  4005ac:       d65f03c0        ret

...

Contents of section .rodata:
 400640 01000200 00000000 48656c6c 6f210000  ........Hello!..
\end{lstlisting}

\myindex{ARM!\Instructions!BL}
Zur Veranschaulichung wollen wir den BL Befehl manuell disassemblieren.\\
\TT{0x97ffffa0} entspricht $0b10010111111111111111111110100000$.
Gemäß \InSqBrackets{\ARMSixFourRef C5.6.26} sind \IT{imm26} die letzten 26 Bit:\\
$imm26 = 0b11111111111111111110100000$.
Das ist \TT{0x3FFFFA0}, aber da das MSB 1 ist, handelt es sich um eine negative Zahl und wir können diese manuell in
eine handlichere Form umwandeln.
Nach den Regeln für Negation (\myref{sec:signednumbers:negation}) invertieren wir alle Bits: (das ergibt
\TT{0b1011111=0x5F}) und addieren dann 1 (\TT{0x5F+1=0x60}).
Die vorzeichenbehaftete Form ist also \TT{-0x60}.
Multiplizieren wir \TT{-0x60} mit 4 (da die im Opcode gespeicherte Adresse durch 4 geteilt worden ist): das ergibt
\TT{-0x180}. 
Berechnen wir nun die Zieladresse: \TT{0x4005a0} + (\TT{-0x180}) = \TT{0x400420} (man beachte: wir betrachten die
Adresse des BL-Befehls, nicht den aktuellen Wert von \ac{PC}, der auch ein anderer sein könnte!).
Die Zieladresse ist also \TT{0x400420}.\\\\
Für mehr Informationen zu Relocs in ARM64 siehe: \ARMELF.
